import md5 from 'js-md5'
import config from '@/request/config'
import storage from '@/storage'
import {
	open,
	toast,
	showLoading
} from '@/utils/uni-tools'

// 请求类型
const methodArr = ['GET', 'POST', 'PUT', 'DELETE']

// 请求
const request = async (params) => {
	setPhoneParams() // 设置手机参数
	return await requestController(params) // 调用请求控制器
}

// 设置手机参数
const setPhoneParams = async () => {
	const palt = storage.get('platform') // 平台
	const imei = storage.get('imei') // 手机IMEI
	if (null == palt || "" == palt || null == imei || "" == imei) { // 若无手机信息
		const [err, res] = await uni.getSystemInfo()
		if (res) {
			if ('ios' == res.platform) { // 设置平台
				storage.set('platform', '1')
			} else if ('android' == res.platform) {
				storage.set('platform', '2')
			} else {
				storage.set('platform', '2')
			}
		}
		storage.set('imei', '1234567890') // 设置IMEI
	}
}

// 请求控制器
const requestController = async (params) => {
	params = setRquestHeader(params) // 设置请求头信息
	params = seturl(params) // 设置请求地址
	params = setRquestMethod(params) // 设置请求动词
	params = setRquestData(params) // 设置请求体信息
	params = await calculateMD5(params) // 生成签名
	if (!params.md5Sign) return // 签名失败则退出
	beforeComm(params) // 通信之前的钩子函数
	return await comm(params) // 通信
}

// 状态管理
const codeManager = (res) => {
	let returnResult // 通信合集
	//返回状态：200返回成功，401重新登录，422后端返回报错，500请求异常
	switch (parseInt(res.statusCode)) {
		case 200:
			returnResult = [null, res.data]
			break;
		case 401:
			toast(res.data.message)
			storage.remove('token')
			open('/pages/common/login/login')
			returnResult = [res.data]
			break;
		case 422:
			toast(res.data.message)
			returnResult = [res.data]
			break;
		case 500:
			if (typeof res.data.message === 'string') {
				toast(res.data.message)
			}
			returnResult = [res.data]
			break;
		default:
			toast(res.data.message)
			returnResult = [res.data]
	}
	return returnResult
}

// 通信
const comm = async params => {
	const {
		url,
		method,
		data,
		contentType,
		md5Sign
	} = params
	const timestamp = (Date.parse(new Date())) / 1000 // 获取时间
	const header = {
		'X-Requested-With': 'XMLHttpRequest',
		'content-type': contentType, // 自定义请求头信息
		'Yw-Sign': md5Sign, // md5签名
		'Yw-Time': timestamp, // 时间戳
		'Authorization': 'Bearer ' + storage.get('token'), // token
		'version': config.apiVersion, // api版本
		'plat': storage.get('platform'), // 当前所处平台
		'sign': storage.get('imei'), // 应用的imei信息
	}
	const [err, res] = await uni.request({ // 请求
		header,
		url,
		method,
		data
	})
	if (params.isLoaing) uni.hideLoading() // 若在loading状态则隐藏loading
	let returnResult // 通信合集
	if (res) { // 通信成功
		if (config.isInfo) console.log(res) // 打印
		returnResult = codeManager(res) // 状态管理
	} else { // 通信失败
		returnResult = [err]
	}
	return returnResult
}

// 通信之前的最后设置
const beforeComm = params => {
	// 测试模式输出信息
	if (config.isInfo) console.log('method==>' + params.method, params.data);
	// 防止表单重复提交
	if (params.isLoaing) showLoading()
}

// 设置请求头信息
const setRquestHeader = params => {
	const {
		method
	} = setRquestMethod(params)
	// 设置header-content-type
	let contentType = "application/x-www-form-urlencoded;charset=UTF-8";
	// 特殊的content-type
	if (method == "PUT") contentType = "application/json;charset=UTF-8";
	params.contentType = contentType
	return params
}

// 设置请求地址
const seturl = params => {
	let url // 最终请求地址
	if (config.apiVersion) {
		url = `${config.baseUrl}/${config.apiVersion}/${params.url}`
	} else {
		url = `${config.baseUrl}/${params.url}`
	}
	params.url = url
	return params
}

// 设置请求动词
const setRquestMethod = params => {
	params.method = params.method.toUpperCase(); // 请求方法
	// 判断是否可用的四个请求类型
	if (methodArr.indexOf(params.method) == -1) throw `确认请求类型-->${method}`
	return params
}

// 设置请求体信息
const setRquestData = params => {
	if ("" == params.data || null == params.data) params.data = {} // 空参数处理
	return params
}

// md5加密生成签名
const calculateMD5 = params => {
	const obj = params.data
	return new Promise(resolve => {
		const key = config.secretKey
		let sign = ''
		// 如果不是对象,也就是说使用的GET和DELETE请求,那么不用加密,直接返回空
		if (Object.prototype.toString.call(obj) != '[object Object]') {
			sign = key + '--' + key
		} else {
			if (JSON.stringify(obj) === '{}') { // 如果是空对象也返回空
				sign = key + '--' + key
			} else { // 非空对象进行逐一加密
				Object.keys(obj).sort().forEach((k) => {
					sign += key + k + '--' + obj[k] + key
				})
			}
		}
		resolve(md5(sign).toUpperCase());
	}).then(res => {
		params.md5Sign = res
		return params
	})
}

export default request
